//
// Created by tcj on 2022/2/23.
//
//协程创建和注销
#ifndef __SYLAR_FIBER_H__
#define __SYLAR_FIBER_H__

#include "memory"
#include "functional"
#include "ucontext.h"
#include "thread.h"

namespace sylar{

//class Scheduler;
class Fiber:public std::enable_shared_from_this<Fiber>{
friend class Scheduler;
public:
    typedef std::shared_ptr<Fiber> ptr;

    enum State{
        //初始化状态--协程刚创建
        INIT,
        //暂停状态--yield状态
        HOLD,
        //执行中状态
        EXEC,
        //结束状态
        TERM,
        //可执行状态
        READY,
        //异常状态
        EXCEPT
    };
private:
//    主协程--每个线程第一个协程的构造
    Fiber();
public:
//    创建新的协程，
//    需要stack--协程栈大小、，
//    还有cb--执行函数,
//    use_caller:是否在mainFiber上调度
    Fiber(std::function<void()> cb,size_t stacksize=0,bool use_caller= false);
    ~Fiber();

//    重置协程函数，并重置状态---
//      pre_state: INIT,TERM,EXCEPT
//      post_state:INIT
    void reset(std::function<void()> cb);

//    切换到当前协程执行-->post_state:EXEC
    void swapIn();

//    切换到后台执行
    void swapOut();

// pre_state:执行为当前线程的主协程
//   将当前线程切换到执行状态
    void call();

//    将当前线程切换到后台
//pre_state:执行的为该协程
//post_state:返回到线程的主协程
    void back();

    uint64_t  getId() const {return m_id;}

public:
//    设置当前协程的运行协程
//    f:运行协程
        static void SetThis(Fiber* f);

//    返回当前所在的协程
    static Fiber::ptr GetThis();

//    协程切换到后台，并且设置为Ready状态
    static void YieldToReady();

//    协程切换到后台，并且设置为Hold状态
    static void YieldToHold();

//    返回当前协程的总数量
    static uint64_t TotalFiber();

    //主协程执行函数
//    post_state:执行完成返回到线程主协程
    static void MainFunc();

    //后续协程执行函数
//    post_sate:执行完成到线程调度协程
    static void CallerMainFunc();

//    获取当前协程id
    static uint64_t GetFiberId();

    State getState() const {return m_state;}

private:
    uint64_t m_id;
//    协程运行栈大小
    uint32_t m_stacksize;
//    协程状态
    State m_state = INIT;
//协程上下文
    ucontext_t m_ctx;
//    协程运行栈指针
    void* m_stack = nullptr;
//协程运行函数
    std::function<void()> m_cb;
};

}



#endif //SERVER_FRAMEWORK_FIBER_H
